package scales.xml.equals
import scales.xml.{QName, Elem, Attribs, Attributes, Attribute, XmlItem, Text, PI, CData, Comment, PullType, EndElem, Misc, Miscs, DocLike, impl}
import impl.EqualsHelpers
import XmlEquals._
import scalaz.Equal._
import scalaz._
import Scalaz._
import SomeDifference.noCalculation
trait XmlComparison[-T] {
def compare( calculate : Boolean , context : ComparisonContext, left : T, right : T) : Option[(XmlDifference[_], ComparisonContext)]
}
trait DefaultQNameEquals {
implicit val qnameEqual : Equal[QName] = equal { (a: QName, b: QName) => a =:= b }
}
class QNameComparison( implicit qe : Equal[QName] ) extends XmlComparison[QName] {
def compare( calculate : Boolean , context : ComparisonContext, left : QName, right : QName ) = {
if (left === right)
None
else
if (calculate)
Some((QNameDifference(left, right), context))
else
noCalculation
}
}
trait QNameEquals {
implicit def qnameComparison( implicit qe : Equal[QName] ) : XmlComparison[QName] = new QNameComparison()(qe)
}
object QNameEquals extends DefaultQNameEquals with QNameEquals {
}
trait DefaultQNameToken {
implicit val defaultQNameTokenComparison : Option[(ComparisonContext, String, String) => Boolean] = None
}
object DefaultQNameToken extends DefaultQNameToken {
}
class XmlItemComparison()(implicit qnameTokenComparison : Option[(ComparisonContext, String, String) => Boolean]) extends XmlComparison[XmlItem] {
def compare( calculate : Boolean , context : ComparisonContext, left : XmlItem, right : XmlItem) : Option[(XmlDifference[_], ComparisonContext)] = {
def check( str : String, str2 : String, isQNameRelevant : Boolean = false ) = {
val res =
if (isQNameRelevant)
compareTokens(context, qnameTokenComparison, str, str2)
else
str == str2
if (res) None
else {
if (calculate)
Some((ItemDifference(left, right), context))
else
noCalculation
}
}
if (left eq right)
None
else (left, right) match {
case (Text(valu), Text(value)) => check(valu, value, true)
case (Comment(com), Comment(comm)) => check(com, comm)
case (CData(cd), CData(cda)) => check(cd, cda, true)
case (PI(ta, valu), PI(tar, value)) =>
check(ta, tar) orElse check(valu, value)
case _ =>
if (calculate)
Some((DifferentTypes(left, right), context))
else
noCalculation
}
}
}
trait DefaultItemEquals {
implicit def defaultXmlItemComparison(implicit qnameTokenComparison : Option[(ComparisonContext, String, String) => Boolean]) : XmlComparison[XmlItem] = new XmlItemComparison()(qnameTokenComparison)
}
object ItemEquals extends DefaultItemEquals {}
class AttributeComparison(implicit eqn : Equal[QName], qnameTokenComparison : Option[(ComparisonContext, String, String) => Boolean]) extends XmlComparison[Attribute] {
import EqualsHelpers.toQName
def compare( calculate : Boolean, context : ComparisonContext, left: Attribute, right : Attribute) : Option[(XmlDifference[_], ComparisonContext)] = {
if (left eq right)
None
else if (!eqn.equal(toQName(left.name), toQName(right.name)))
if (calculate)
Some((AttributeNameDifference( left, right), context))
else
noCalculation
else {
if (!compareTokens( context, qnameTokenComparison, left.value, right.value ))
if (calculate)
Some((AttributeValueDifference( left, right), context))
else
noCalculation
else
None
}
}
}
trait DefaultAttributeEquals {
implicit def defaultAttributeComparison(implicit qe : Equal[QName], qnameTokenComparison : Option[(ComparisonContext, String, String) => Boolean]) : XmlComparison[Attribute] = new AttributeComparison()(qe, qnameTokenComparison)
}
object AttributeEquals extends DefaultAttributeEquals with DefaultQNameEquals {}
trait ExactQName{
implicit def prefixAttributeComparison(implicit qnameTokenComparison : Option[(ComparisonContext, String, String) => Boolean]) = new AttributeComparison()(equal { (a: QName, b: QName) => a.====(b) }, qnameTokenComparison)
}
object ExactQName extends ExactQName {}
class AttributesComparison( implicit ac : XmlComparison[Attribute]) extends XmlComparison[Attributes] {
def compare( calculate : Boolean, context : ComparisonContext, left : Attributes, right : Attributes) : Option[(XmlDifference[_], ComparisonContext)] = {
import EqualsHelpers._
import scales.utils.collectFirst
if (left eq right)
None
else
if (left.size != right.size)
if (calculate)
Some((DifferentNumberOfAttributes(left,right), context))
else
noCalculation
else
collectFirst[Attribute, (XmlDifference[_], ComparisonContext)](left){
x1 =>
right( x1.name ).cata( x2 => {
val r = ac.compare(calculate, context, x1, x2)
if (r.isDefined) {
if (calculate)
Some( (DifferentValueAttributes( left, right, x1 ), context) )
else
noCalculation
} else None
} ,
if (calculate)
Some( ( MissingAttributes( left, right, x1 ), context) )
else
noCalculation
)
}
}
}
trait DefaultAttributesEquals {
implicit def defaultAttributesComparison(implicit ac : XmlComparison[Attribute]) : XmlComparison[Attributes] = new AttributesComparison()( ac )
}
object AttributesEquals extends DefaultAttributesEquals
with DefaultAttributeEquals with DefaultQNameEquals {}